package aes

import (
	"bytes"
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"encoding/base64"
	"fisherman/common/logger"
	"fmt"
	"io"
)

// EncryptString AES文本加密 (CBC 模式)
func EncryptString(content, key string) string {
	return EncryptStringByKey(content, key, "")
}

// EncryptStringByKey AES文本加密 (CBC 模式)
func EncryptStringByKey(content string, key, iv string) string {
	if content == "" {
		log.Errorf("AESEncryptString传入的content位空")
		return ""
	}
	if key == "" {
		log.Errorf("AESEncryptString的key位空")
		return ""
	}

	// 转换 key 为字节数组
	keyBytes := []byte(key)

	// 验证 key 的长度
	if len(keyBytes) != 16 && len(keyBytes) != 24 && len(keyBytes) != 32 {
		log.Error("key length must be 16, 24, or 32 bytes")
		return ""
	}

	// 随机生成 iv
	var ivBytes []byte
	if iv == "" {
		ivBytes = make([]byte, aes.BlockSize)
		if _, err := io.ReadFull(rand.Reader, ivBytes); err != nil {
			log.Errorf("failed to generate random iv: ", err)
			return ""
		}
	} else {
		ivBytes = []byte(iv)
	}

	// 初始化 AES 密码块
	block, err := aes.NewCipher(keyBytes)
	if err != nil {
		log.Error(err)
		return ""
	}

	// pkcs5Padding
	plainTextBytes := pkcs5Padding([]byte(content), block.BlockSize())

	// 初始化 CBC 加密器
	mode := cipher.NewCBCEncrypter(block, ivBytes)
	cipherText := make([]byte, len(plainTextBytes))
	mode.CryptBlocks(cipherText, plainTextBytes)

	var result []byte
	if iv == "" {
		pos := 5
		result = make([]byte, aes.BlockSize+len(cipherText))
		copy(result, cipherText[:pos])
		copy(result[pos:], ivBytes)
		copy(result[pos+aes.BlockSize:], cipherText[pos:])
	} else {
		result = cipherText
	}
	return base64.StdEncoding.EncodeToString(result)
}

// AES文本解密 (CBC 模式)
func DecryptString(content, key string) string {
	return DecryptStringByKey(content, key, "")
}

// AES文本解密 (CBC 模式)
func DecryptStringByKey(content, key, iv string) string {
	if content == "" {
		log.Errorf("AESDecryptString传入的content位空")
		return ""
	}
	if key == "" {
		log.Errorf("AESDecryptString的key位空")
		return ""
	}

	// 转换 key 为字节数组
	keyBytes := []byte(key)

	// 验证 key 的长度
	if len(keyBytes) != 16 && len(keyBytes) != 24 && len(keyBytes) != 32 {
		log.Error("key length must be 16, 24, or 32 bytes")
		return ""
	}

	// 解码 base64 密文
	decoded, err := base64.StdEncoding.DecodeString(content)
	if err != nil {
		log.Error(err)
		return ""
	}

	// 拆分 iv 和密文
	var ivBytes, cipherText []byte
	if iv == "" {
		pos := 5
		ivBytes = decoded[pos : pos+aes.BlockSize]
		cipherText = make([]byte, len(decoded)-aes.BlockSize)
		copy(cipherText, decoded[:pos])
		copy(cipherText[pos:], decoded[pos+aes.BlockSize:])
	} else {
		ivBytes = []byte(iv)
		cipherText = decoded
	}

	// 初始化 AES 密码块
	block, err := aes.NewCipher(keyBytes)
	if err != nil {
		log.Error(err)
		return ""
	}

	// 检查密文长度是否正确
	if len(cipherText)%block.BlockSize() != 0 {
		log.Error("cipherText length is not a multiple of the block size")
		return ""
	}

	// 初始化 CBC 解密器
	mode := cipher.NewCBCDecrypter(block, ivBytes)
	plainText := make([]byte, len(cipherText))
	mode.CryptBlocks(plainText, cipherText)

	// 去除 pkcs5Padding
	plainText, err = pkcs5UnPadding(plainText)
	if err != nil {
		log.Errorf("执行pkcs5UnPadding(plainText)失败：%v", err)
		return ""
	}

	return string(plainText)
}

func pkcs5Padding(data []byte, blockSize int) []byte {
	padding := blockSize - len(data)%blockSize
	padtext := bytes.Repeat([]byte{byte(padding)}, padding)
	return append(data, padtext...)
}

func pkcs5UnPadding(data []byte) ([]byte, error) {
	length := len(data)
	if length == 0 {
		return nil, fmt.Errorf("invalid padding size")
	}
	padding := int(data[length-1])
	if padding > length || padding == 0 {
		return nil, fmt.Errorf("invalid padding value")
	}
	return data[:length-padding], nil
}
